home *** CD-ROM | disk | FTP | other *** search
- /*******************************************************************************
- ProcessChecker Demo
- Example submitted by David Clegg
-
- This unit contains the ProcessChecker class, which is responsible for
- monitoring, stopping and restarting processes.
- *******************************************************************************/
- using System;
- using System.IO;
- using System.Windows.Forms;
- using System.Threading;
- using System.Diagnostics;
-
- namespace ProcessChecker {
-
- //Delegate for Process Checker Event notification
- public delegate void ProcessCheckerEventNotify(object sender, ProcessCheckerEventArgs args);
-
- /// <summary>
- /// Derived EventArgs class used by ProcessCheckerEventNotify delegate
- /// </summary>
- public class ProcessCheckerEventArgs : EventArgs {
- string fMessage;
- public ProcessCheckerEventArgs(string message) {
- fMessage = message;
- }
-
- public string Message {
- get{return fMessage;}
- }
- }
-
- /// <summary>
- /// Class to handle the Process monitoring. As I become more
- /// preficient, I will host this in a seperate thread.
- /// </summary>
- public class ProcessChecker {
- private ProcessCheckerSettings fSettings;
- private bool fSuspended = false;
- private System.Windows.Forms.Timer timCheck;
-
- public ProcessChecker(ProcessCheckerSettings settings) {
- fSettings = settings;
- InitTimer();
- InitSettings();
- }
-
- public event ProcessCheckerEventNotify ProcessCheckerEvent;
-
- /// <summary>
- /// Returns a reference to the ProcessCheckerSettings instance.
- /// </summary>
- public ProcessCheckerSettings Settings {
- get {return fSettings;}
- }
-
- /// <summary>
- /// Temporarily suspends process checking without affecting the
- /// ProcessCheckerSettings.Enabled property.
- /// </summary>
- public void Suspend() {
- fSuspended = true;
- }
-
- /// <summary>
- /// Resumes process checking, if it was suspended.
- /// </summary>
- public void Resume() {
- fSuspended = false;
- }
-
- /// <summary>
- /// Create the timer, and attach the Tick event.
- /// </summary>
- private void InitTimer() {
- //There is a Timer class in System.Threading and System.Windows.Forms.
- //As this is a simple single-threaded implementation, for now we
- //will use the WinForms one.
- timCheck = new System.Windows.Forms.Timer();
- timCheck.Tick += new EventHandler(timCheck_Tick);
- SetTimerInterval();
- }
-
- /// <summary>
- /// Create the ProcessCheckerSettings instance, and attach the event
- /// handlers to notify when the instance is loaded or saved.
- /// </summary>
- private void InitSettings() {
- fSettings.SettingsLoaded += new EventHandler(Settings_Updated);
- fSettings.SettingsSaved += new EventHandler(Settings_Updated);
-
- //As the event handlers are attached after the settings are
- //initially loaded from disk, we need to fire the event manually.
- Settings_Updated(this, null);
- }
-
- /// <summary>
- /// Event handler called if the ProcessCheckerSettings instance is loaded
- /// or saved. As we are only interested in determining that the settings
- /// may have changed (and not what caused the change), we can share the
- /// event handler.
- /// </summary)
- private void Settings_Updated(object sender, EventArgs args) {
- SetTimerInterval();
- }
-
- /// <summary>
- /// Sets the interval for the timer used to trigger the process checking
- /// </summary>
- private void SetTimerInterval() {
- //CheckFrequency is stored in seconds, but we need to convert it
- //to milliseconds for the timer.
- int lInterval = fSettings.CheckFrequency * 1000;
-
- //Timer class will throw an exception if we attempt to assign an
- //interval with a zero value
- if (lInterval > 0) {
- timCheck.Interval = lInterval;
- timCheck.Enabled = fSettings.Enabled;
- }
- else {
- //Ensure timer is disabled
- timCheck.Enabled = false;
- fSettings.Enabled = false;
- fSettings.Save();
- }
- }
-
- private void timCheck_Tick(object sender, System.EventArgs e) {
- CheckProcesses();
- }
-
- /// <summary>
- /// Iterate through all monitored processes to check whether they are
- /// still running.
- /// </summary>
- private void CheckProcesses() {
- Process[] processes;
- if (fSuspended != true)
- foreach (WatchedProcess watchedProcess in fSettings.WatchedProcesses)
- {
- processes = CheckProcess(watchedProcess.ProcessPath);
- if (processes.Length == 0) {
- //No instances of watchedProcess running, so re-start it
- RestartProcess(watchedProcess);
- if (fSettings.RestartOneProcess)
- //We only restart one process each time we check
- //running processes. Any subsequent processes that have
- //unexpectedly terminated will be caught next time.
- break;
- }
- else
- foreach (Process runningProcess in processes)
- //At least one instance of watchedProcess running,
- //so check that the instance(s) are still responding.
- if (watchedProcess.CheckResponding)
- if (runningProcess.Responding == false) {
- //Process not responding, so re-start it.
- NotifyEvent(string.Format("{0} - not responding",
- runningProcess.ProcessName));
- StopProcess(runningProcess);
- RestartProcess(watchedProcess);
- if (fSettings.RestartOneProcess)
- //Only restarting one process per check.
- break;
- }
- }
- }
-
- /// <summary>
- /// Check to see whether the specified process is still running.
- /// Returns an array of Process instances if the process has at least one
- /// running instance.
- /// </summary>
- public Process[] CheckProcess(string processPath) {
- string lProcessName = Path.GetFileNameWithoutExtension(processPath);
- return Process.GetProcessesByName(lProcessName);
- }
-
- /// <summary>
- /// Restart a process.
- /// </summary>
- private void RestartProcess(WatchedProcess process) {
- StopDependantProcesses(process);
- Process startProcess = new Process();
- startProcess.StartInfo.FileName = process.ProcessPath;
- startProcess.StartInfo.WorkingDirectory = Path.GetDirectoryName(process.ProcessPath);
- try {
- startProcess.Start();
- NotifyEvent(string.Format("{0} - Process restarted", process.ProcessName));
- }
- catch (Exception exception) {
- NotifyEvent(string.Format("Error starting {0} - {1}",
- process.ProcessName, exception.Message));
- }
- }
-
- /// <summary>
- /// Iterate through, and terminate, all dependant processes.
- /// </summary>
- private void StopDependantProcesses(WatchedProcess process) {
- Process[] dependantProcesses;
- foreach(ProcessDetails dependantDetails in process.DependantProcesses) {
- dependantProcesses = CheckProcess(dependantDetails.ProcessPath);
- foreach (Process dependant in dependantProcesses)
- StopProcess(dependant);
- }
- }
-
- /// <summary>
- /// Stop a process.
- /// </summary>
- private void StopProcess(Process process) {
- //Attempt to stop the process 'nicely' by sending a Close message
- //to the processes main window
- process.CloseMainWindow();
- //Give the message a chance to be processed
- Thread.Sleep(100);
- if (process.HasExited == false) {
- //CloseMainWindow didn't work so attempt a more forceful
- //shutdown. Process.Kill forces an immediate termination of the
- //process.
- process.Kill();
- Thread.Sleep(100);
- if (process.HasExited == false)
- //Still running, but its time to admit defeat :-(
- NotifyEvent(string.Format("{0} - Process termination failed",
- process.ProcessName));
- else
- NotifyEvent(string.Format("{0} - Process killed",
- process.ProcessName));
- }
- else
- NotifyEvent(string.Format("{0} - Process stopped",
- process.ProcessName));
- }
-
- /// <summary>
- /// Send a Process Checker Event notification.
- /// </summary>
- private void NotifyEvent(string eventDetails) {
- ProcessCheckerEventArgs args = new ProcessCheckerEventArgs(eventDetails);
- ProcessCheckerEvent(this, args);
- }
- }
- }
-